package com.ruoyi.ora.netty.channel.stick;

import com.ruoyi.common.utils.ByteUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.util.Arrays;

/**
 * 按帧头，长度 再判断帧尾组包
 */
public class HeadLengthTailFieldHandler extends SimpleChannelInboundHandler<byte[]> {

    private byte[] byte_buffer;     //数据缓冲区

    private byte[] headBytes;
    private byte[] tailBytes;
    private int lengthFieldOffset;
    private int lengthFieldLength;
    private int maxFrameLength;
    private int frameLength;
    private int compensateFrameLength;

    public HeadLengthTailFieldHandler(byte[] headBytes, byte[] tailBytes, int lengthFieldOffset, int lengthFieldLength, int frameLength, int compensateFrameLength) {
        this.headBytes = headBytes;
        this.tailBytes = tailBytes;
        this.lengthFieldOffset = lengthFieldOffset;
        this.lengthFieldLength = lengthFieldLength;
        this.frameLength = frameLength;
        this.compensateFrameLength = compensateFrameLength;
        this.maxFrameLength = 65535;
        this.byte_buffer = null;
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] bytes) throws Exception {
        this.byte_buffer = ByteUtil.byteMerger(this.byte_buffer, bytes);
        while (true){
            //找头
            int headIndex = ByteUtil.byteIndexOf(headBytes, this.byte_buffer);
            if (headIndex >= 0){
                //判长度
                int length = frameLength;
                if (frameLength == 0){
                    byte[] length_bytes = ByteUtil.subBytes(this.byte_buffer, headIndex + lengthFieldOffset, lengthFieldLength);
                    if (length_bytes == null) {
                        //如果找到头了 长度获取为空则直接保留头后面的数据
                        this.byte_buffer = ByteUtil.subBytes(this.byte_buffer, headIndex);
                        break;
                    }else {
                        length = ByteUtil.bytesToInt(length_bytes);
                    }
                }
                //长度补加
                length += compensateFrameLength;

                // 数据正好为一帧 为了不重复复制
                if (headIndex == 0 && length == this.byte_buffer.length){
                    if (tailBytes == null){
                        ctx.fireChannelRead(this.byte_buffer);
                        this.byte_buffer = null;
                    }else {
                        //判断帧尾
                        byte[] data_tail_bytes = ByteUtil.subBytes(this.byte_buffer, this.byte_buffer.length - tailBytes.length);
                        if (Arrays.equals(data_tail_bytes, tailBytes)){
                            // 验证成功 传递
                            ctx.fireChannelRead(this.byte_buffer);
                        }
                        // 如果没有验证成功也丢了  数据肯定有问题
                        this.byte_buffer = null;
                    }
                }else {
                    //获取一个完整帧
                    byte[] item_bytes = ByteUtil.subBytes(this.byte_buffer, headIndex, length);
                    if (item_bytes != null){
                        if (tailBytes == null){
                            ctx.fireChannelRead(item_bytes);
                            //缓冲区后移
                            this.byte_buffer = ByteUtil.subBytes(this.byte_buffer, length + headIndex);
                        }else {
                            //判断帧尾
                            byte[] data_tail_bytes = ByteUtil.subBytes(item_bytes, item_bytes.length - tailBytes.length);
                            if (Arrays.equals(data_tail_bytes, tailBytes)){
                                // 验证成功 传递
                                ctx.fireChannelRead(item_bytes);
                                //缓冲区后移
                                this.byte_buffer = ByteUtil.subBytes(this.byte_buffer, length + headIndex);
                            }else {
                                //下一个头重新找
                                this.byte_buffer = ByteUtil.subBytes(this.byte_buffer, headIndex + headBytes.length);
                            }
                        }
                    }else {
                        //如果找到头了 完整帧为空则直接保留头后面的数据
                        this.byte_buffer = ByteUtil.subBytes(this.byte_buffer, headIndex);
                        break;
                    }
                }
            }else {
                //如果超过最大帧长度还没有找到头则直接丢
                if (this.byte_buffer != null && this.byte_buffer.length > this.maxFrameLength){
                    this.byte_buffer = null;
                }
                //找不到头不处理直接过
                break;
            }
        }
    }
}
